#include "lxz_config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "lxz_types.h"
#include "lxz_version.h"
#include "lxz_ring.h"
#include "lxz_string.h"
#include "lxz_dstring.h"
#include "lxz_runlog.h"
#include "lxz_debug.h"
#include "lxz_exec.h"
#include "os_port.h"

#include "lxz_atc_req.h"
#include "latserver.h"
#include "lxz_urc_table.h"
#include "lxz_dbg_vmem.h"

static uint32 ThreadTCPService(void* lpParam);
static sint32 udt_f_tcpserver_start(uint16 u_svr_port);

static sint32 udt_f_tcpserver_start(uint16 u_svr_port)
{
    sint32 i_ret_val = 0;

    sint32 svrsock, actsock;
    sint32 i_op_status = 0;
    latos_context_t * p_udt_ctxt = NULL;

    if((svrsock = osp_socket_f_open(2/*AF_INET*/,1/*SOCK_STREAM*/,0)) == 0)
    {
        OS_DBG_URC(("tcpserver: osp_socket_f_open fail\r\n"));
        return -1;
    }

    if(osp_socket_f_bind(svrsock, "0.0.0.0", u_svr_port) == 0)
    {
        OS_DBG_URC(("tcpserver: osp_socket_f_bind fail\r\n"));
		osp_socket_f_close(svrsock);
        return -1;
    }

    if(osp_socket_f_listen(svrsock, UDT_MAX_BACK_LOG) == 0)
    {
        OS_DBG_URC(("tcpserver: osp_socket_f_listen fail;\r\n"));
		osp_socket_f_close(svrsock);
        return -1;
    }

    while (1)
    {
        p_udt_ctxt = NULL;

        actsock = osp_socket_f_accept(svrsock);
        if (actsock == -1)
        {
            osp_timer_f_sleep(1);
            continue;
        }

        p_udt_ctxt = (latos_context_t *)malloc(sizeof(latos_context_t));
        if(p_udt_ctxt == NULL)
        {
            osp_socket_f_close(actsock);
            osp_socket_f_close(svrsock);

            i_ret_val = -1;
            break;
        }

        memset(p_udt_ctxt, 0, sizeof(latos_context_t));
        p_udt_ctxt->p_rw_buff = (sint08 *)malloc(UDT_MAX_BUFF_SIZE);
        if(p_udt_ctxt->p_rw_buff == NULL)
        {
            osp_socket_f_close(actsock);
            osp_socket_f_close(svrsock);
            free(p_udt_ctxt);

            i_ret_val = -1;
            break;
        }

        p_udt_ctxt->lsockfd = svrsock;
        p_udt_ctxt->csockfd = actsock;
        osp_socket_f_nonblock(actsock, 1);
        i_op_status = osp_thread_f_open(ThreadTCPService, p_udt_ctxt,
            &(p_udt_ctxt->iThreadID));

        if (i_op_status == 0)
        {
            osp_socket_f_close(p_udt_ctxt->csockfd);
            free(p_udt_ctxt->p_rw_buff);
            free(p_udt_ctxt);
        }
    }

    return i_ret_val;
}

static uint32 udt_f_tcpserver_LATServer(void* pctxt)
{
    latos_context_t * p_udt_ctxt = (latos_context_t *)pctxt;

    sint32 i_len_recved = 0;
    sint32 i_echo_times = 0;

    sint32 i_vsp_id = 0;
    lxzat_spcfg_t * p_cur_spcfg = NULL;

    lxz_vmem_f_report();

    i_vsp_id = lxzat_spcomm_f_find();
    if (i_vsp_id == -1)
    {
        osp_socket_f_close(p_udt_ctxt->csockfd);
        free(p_udt_ctxt->p_rw_buff);
        free(p_udt_ctxt);
    }

    lxzat_f_init(i_vsp_id);
    p_cur_spcfg = lxzat_spcomm_f_get(i_vsp_id);
    p_cur_spcfg->u_vsp_fd = p_udt_ctxt->csockfd;

    OS_DBG_LOG(("iThreadID:0x%08X, i_vsp_id:%d, opened.\r\n", p_udt_ctxt->iThreadID, i_vsp_id));
    OS_DBG_URC(("iThreadID:0x%08X, i_vsp_id:%d, opened.\r\n", p_udt_ctxt->iThreadID, i_vsp_id));
    while (1)
    {
        sint32 i_nb_bytes = 0;

        i_nb_bytes = osp_socket_f_getavailable(p_udt_ctxt->csockfd);
        if (i_nb_bytes > 0)
        {
            memset(p_udt_ctxt->p_rw_buff, 0, UDT_DEF_BUFF_SIZE);
            i_len_recved = osp_socket_f_read(p_udt_ctxt->csockfd,
                p_udt_ctxt->p_rw_buff, UDT_DEF_BUFF_SIZE);
            
            lxzat_f_echo(i_vsp_id, p_udt_ctxt->p_rw_buff, i_len_recved);
            
            lxzat_main(i_vsp_id, p_udt_ctxt->p_rw_buff, i_len_recved);
        }

        /* step2: all task that active will be running */
        lxzat_task_f_DoCycle();

        if (p_cur_spcfg->i_link_mode == E_LSMX_CLOSING)
        {
            break;
        }

        osp_timer_f_sleep(1);
    }

    OS_DBG_LOG(("iThreadID:0x%08X, i_vsp_id:%d, closed.\r\n", p_udt_ctxt->iThreadID, i_vsp_id));
    OS_DBG_URC(("iThreadID:0x%08X, i_vsp_id:%d, closed.\r\n", p_udt_ctxt->iThreadID, i_vsp_id));

    lxzat_f_reset(i_vsp_id);
    osp_socket_f_close(p_udt_ctxt->csockfd);
    free(p_udt_ctxt->p_rw_buff);
    free(p_udt_ctxt);

    lxz_vmem_f_report();

    return 0;
}

static uint32 ThreadTCPService(void* lpParam)
{
    uint32 u_thread_id = 0;
    latos_context_t * p_udt_ctxt = (latos_context_t *)lpParam;

    /* Send What Received, all data that from peer will send to peer */
    if (p_udt_ctxt != NULL)
    {
        u_thread_id = p_udt_ctxt->iThreadID;
        OS_DBG_LOG(("iThreadID:0x%08X, TCPService, start!\r\n", u_thread_id));
        OS_DBG_URC(("iThreadID:0x%08X, TCPService, start!\r\n", u_thread_id));
        srand((uint32)time(0));
        udt_f_tcpserver_LATServer(p_udt_ctxt);

        OS_DBG_LOG(("iThreadID:0x%08X, TCPService, stop!\r\n", u_thread_id));
        OS_DBG_URC(("iThreadID:0x%08X, TCPService, stop!\r\n", u_thread_id));
    }

    return 0;
}

int latos_server_main(uint16 u_svr_port)
{
	OS_DBG_LOG(("$Author: tangtao1170@163.com;\r\n"));
    OS_DBG_LOG(("$ID: %s-v%s;\r\n", LXZAT_SW_NAME, LXZAT_SW_VERSION));
    OS_DBG_LOG(("$Compile: %s %s;\r\n", LXZAT_SW_BUILD_DATE, LXZAT_SW_BUILD_TIME));
    OS_DBG_LOG(("$Simulator: Ready, TCP-Port:%d;\r\n\r\n", u_svr_port));

	OS_DBG_URC(("$Author: tangtao1170@163.com;\r\n"));
    OS_DBG_URC(("$ID: %s-v%s;\r\n", LXZAT_SW_NAME, LXZAT_SW_VERSION));
    OS_DBG_URC(("$Compile: %s %s;\r\n", LXZAT_SW_BUILD_DATE, LXZAT_SW_BUILD_TIME));
    OS_DBG_URC(("$Simulator: Ready, TCP-Port:%d;\r\n\r\n", u_svr_port));

    osp_socket_f_init();
    udt_f_tcpserver_start(u_svr_port);
    osp_socket_f_uninit();

    return 0;
}

sint32 latos_reboot(sint32 i_vsp_id)
{
    lxzat_spcfg_t * p_cur_spcfg = NULL;

    p_cur_spcfg = lxzat_spcomm_f_get(i_vsp_id);
    p_cur_spcfg->i_link_mode = E_LSMX_CLOSING;
    
    return 1;
}